home *** CD-ROM | disk | FTP | other *** search
/ Aminet 30 / Aminet 30 (1999)(Schatztruhe)[!][Apr 1999].iso / Aminet / util / conv / makedoc-palm.lha / makedoc8.cc < prev   
C/C++ Source or Header  |  1998-09-20  |  33KB  |  1,147 lines

  1.  
  2. // MakeDoc
  3. // version 0.8
  4. //
  5. // Compresses text files into a format that is ready to export to a Pilot
  6. // and work with Rick Bram's PilotDOC reader.
  7. //
  8. // Freeware
  9. //
  10. // ver 0.6   enforce 31 char limit on database names
  11. // ver 0.7   change header and record0 to structs
  12. // ver 0.7a  minor mispellings and portability issues
  13. /**********************************************************************
  14.  * Rick,
  15.  *
  16.  * I made some more changes to fix another portability problem.  It seems
  17.  * that SOME compilers will pad a structure to a DWORD boundary when you
  18.  * use the sizeof operator.  In particular, for the Solaris compiler, the
  19.  * 78 byte tDocHeader structure is reported as having 80 bytes.  This shifts
  20.  * EVERYTHING by two bytes and wreaks havoc in the generated .prc file.
  21.  * I fixed this (look at the comments in struct tDocHeader and the DOCHEADSZ
  22.  * definition) in the two places it occurred.
  23.  *
  24.  * I also fixed a spelling error in an error message.
  25.  *
  26.  * I also changed the usage message to say this is version 0.7a (rather than
  27.  * 0.6).
  28.  *
  29.  * I also changed the return type of main() to be int and added various
  30.  * calls to exit() as needed.  Needed for portability and correctness.
  31.  *
  32.  * -- Harold Bamford
  33.  **********************************************************************/
  34. //
  35. // Modifications by Kadar Tanuwidjaja (ktan8@dgs.monash.edu.au)
  36. // ver 0.8   add -q for quiet mode
  37. //           add -p for private flag
  38. //           add -c for category
  39. //           add -i for info (title, private flag, category)
  40. //           add -m for changing title, category or private flag
  41. //           default for out-filename is in-filename.pdb (encoding mode)
  42. //           default for title is in-filename (encoding mode)
  43. //           default for out-filename is stdout (decoding mode)
  44. //           modify command syntax, but still maintain backward
  45. //               compatibiliy (see makedoc -h for more details)
  46.  
  47. #define UNIX 1
  48. #ifdef sparc
  49. #       ifndef UNIX
  50. #       define UNIX 1
  51. #       endif
  52. #endif
  53.  
  54. #include <stdio.h>
  55. #include <stdlib.h>
  56. #include <string.h>
  57.  
  58. //template<class A> A max(const A& a, const A& b) {return (a<b) ? b : a;}
  59. #define max(a,b) ((a>b) ? a : b)
  60.  
  61. typedef unsigned char byte;
  62. typedef unsigned long DWORD;
  63. typedef unsigned short WORD;
  64. #define DISP_BITS 11
  65. #define COUNT_BITS 3
  66.  
  67. // all numbers in these structs are big-endian, MAC format
  68. struct tDocHeader {
  69.         char sName[32];         // 32 bytes
  70.         DWORD dwUnknown1;       // 36   2b file attribute & 2b version
  71.         DWORD dwTime1;          // 40   Creation Date
  72.         DWORD dwTime2;          // 44   Modification Date
  73.         DWORD dwTime3;          // 48   Last Backup Date
  74.         DWORD dwLastSync;       // 52   Modication Number
  75.         DWORD ofsSort;          // 56   AppInfo Area
  76.         DWORD ofsCatagories;    // 60   SortInfo Area
  77.         DWORD dwCreator;        // 64   Database Type
  78.         DWORD dwType;           // 68   Creator ID
  79.         DWORD dwUnknown2;       // 72   Unique ID seed
  80.         DWORD dwUnknown3;       // 76   Next Record List ID
  81.         WORD  wNumRecs;         // 78   Number of Records
  82. };
  83.  
  84. // Some compilers pad structures out to DWORD boundaries so using sizeof()
  85. // doesn't give the intended result.
  86. #define DOCHEADSZ 78
  87.  
  88. struct tDocRecord0 {
  89.         WORD wVersion;          // 1=plain text, 2=compressed
  90.         WORD wSpare;
  91.         DWORD dwStoryLen;       // in bytes, when decompressed
  92.         WORD wNumRecs;          // text records only; equals tDocHeader.wNumRec
  93. s-1
  94.         WORD wRecSize;          // usually 0x1000
  95.         DWORD dwSpare2;
  96. };
  97.  
  98. ////////////// utilities //////////////////////////////////////
  99.  
  100. WORD SwapWord21(WORD r)
  101. {
  102.         return (r>>8) + (r<<8);
  103. }
  104. WORD SwapWord12(WORD r)
  105. {
  106.         return r;
  107. }
  108. DWORD SwapLong4321(DWORD r)
  109. {
  110.         return  ((r>>24) & 0xFF) + (r<<24) + ((r>>8) & 0xFF00) + ((r<<8) & 0xFF
  111. 0000);
  112. }
  113. DWORD SwapLong1234(DWORD r)
  114. {
  115.         return r;
  116. }
  117.  
  118. WORD (*SwapWord)(WORD r) = NULL;
  119. DWORD (*SwapLong)(DWORD r) = NULL;
  120.  
  121. // copy bytes into a word and double word and see how they fall,
  122. // then choose the appropriate swappers to make things come out
  123. // in the right order.
  124. int SwapChoose()
  125. {
  126.   union { char b[2]; WORD w; } w;
  127.   union { char b[4]; DWORD d; } d;
  128.  
  129.   strncpy(w.b, "\1\2", 2);
  130.   strncpy(d.b, "\1\2\3\4", 4);
  131.  
  132.   if (w.w == 0x0201)
  133.     SwapWord = SwapWord21;
  134.   else if (w.w == 0x0102)
  135.     SwapWord = SwapWord12;
  136.   else
  137.     return 0;
  138.  
  139.   if (d.d == 0x04030201)
  140.     SwapLong = SwapLong4321;
  141.   else if (d.d == 0x01020304)
  142.     SwapLong = SwapLong1234;
  143.   else
  144.     return 0;
  145.  
  146.   return 1;
  147. }
  148.  
  149. // replacement for strstr() which deals with 0's in the data
  150. byte* memfind(byte* t, int t_len, byte* m, int m_len)
  151. {
  152.         int i;
  153.  
  154.         for (i = t_len - m_len + 1 ; i>0; i--, t++)
  155.                 if (t[0]==m[0] && memcmp(t,m,m_len)==0)
  156.                         return t;
  157.         return 0;
  158. }
  159.  
  160.  
  161. /////////////////////////////////////////////////////////////////////////////
  162. /////////////////////////////////////////////////////////////////////////////
  163. /////////////////////                                  //////////////////////
  164. /////////////////////      tBuf class                  //////////////////////
  165. /////////////////////                                  //////////////////////
  166. /////////////////////////////////////////////////////////////////////////////
  167. /////////////////////////////////////////////////////////////////////////////
  168.  
  169.  
  170. struct tBuf {
  171.         byte* buf;
  172.         unsigned len;
  173.  
  174.         tBuf() {buf = new byte[len = 6000];};
  175.         ~tBuf() {       if (buf) delete[] buf; }
  176.         unsigned Len() const {  return len;     }
  177.  
  178.         unsigned RemoveBinary();
  179.         unsigned Decompress();
  180.         unsigned Compress();
  181.         unsigned Issue(byte src, int& bSpace);
  182.         unsigned DuplicateCR();
  183.         void Clear() {delete[] buf; buf = new byte[len = 6000]; }
  184.         void Dump() {printf("\nbuffer len=%d",len);}
  185. };
  186.  
  187.  
  188.  
  189. //
  190. // Issue()
  191. //
  192. // action: handle the details of writing a single
  193. //              character to the compressed stream
  194. //
  195. unsigned
  196. tBuf::Issue(byte src, int& bSpace)
  197. {
  198.         int iDest = len;
  199.         byte* dest = buf;
  200.  
  201.         // if there is an outstanding space char, see if
  202.         // we can squeeze it in with an ASCII char
  203.         if (bSpace)
  204.         {
  205.                 if (src>=0x40 && src<=0x7F)
  206.                         dest[iDest++] = src ^ 0x80;
  207.                 else
  208.                 {
  209.                         // couldn't squeeze it in, so issue the space char by i
  210. tself
  211.                         // most chars go out simple, except the range 1...8,0x8
  212. 0...0xFF
  213.                         dest[iDest++] = ' ';
  214.                         if (src<0x80 && (src==0 || src>8) )
  215.                                 dest[iDest++] = src;
  216.                         else
  217.                                 dest[iDest++] = 1, dest[iDest++] = src;
  218.                 }
  219.                 // knock down the space flag
  220.                 bSpace = 0;
  221.         }
  222.         else
  223.         {
  224.                 // check for a space char
  225.                 if (src==' ')
  226.                         bSpace = 1;
  227.                 else
  228.                 {
  229.                         if (src<0x80 && (src==0 || src>8))
  230.                                 dest[iDest++] = src;
  231.                         else
  232.                                 dest[iDest++] = 1, dest[iDest++] = src;
  233.  
  234.                 }
  235.         }
  236.         len = iDest;
  237.         return iDest;
  238. }
  239.  
  240. //
  241. // Compress
  242. //
  243. // params:      none
  244. //
  245. // action:      takes the given buffer,
  246. //                                      and compresses
  247. //                                      the original data down into a second bu
  248. ffer
  249. //
  250. // comment:     This version make heavy use of walking pointers.
  251. //
  252. unsigned tBuf::Compress()
  253. {
  254.         int i,j;
  255.         int bSpace = 0;
  256.  
  257.         // run through the input buffer
  258.         byte* pBuffer;          // points to the input buffer
  259.         byte* pHit;             // points to a walking test hit; works upwards
  260. on successive matches
  261.         byte* pPrevHit;         // previous value of pHit
  262.         byte* pTestHead;        // current test string
  263.         byte* pTestTail;        // current walking pointer; one past the curren
  264. t test buffer
  265.         byte* pEnd;             // 1 past the end of the input buffer
  266.  
  267.         pHit = pPrevHit = pTestHead = pBuffer = buf;
  268.         pTestTail = pTestHead+1;
  269.         pEnd = buf + len;
  270. //printf("pointers %x %x",pTestTail, pEnd);
  271. //printf("\nstart compression buf len=%d",len);
  272.  
  273.         // make a dest buffer and reassign the local buffer
  274.         buf = new byte[6000];
  275.         len = 0;                // used to walk through the output buffer
  276.  
  277.         // loop, absorbing one more char from the input buffer on each pass
  278.         for (; pTestHead != pEnd; pTestTail++)
  279.         {
  280. //printf("\npointers pTestHead %x pTestTail %x pTestHead[]=%x %x",pTestHead, pT
  281. estTail, pTestHead[0], pTestHead[1]);
  282.                 // establish where the scan can begin
  283.                 if (pTestHead - pPrevHit > ((1<<DISP_BITS)-1))
  284.                         pPrevHit = pTestHead - ((1<<DISP_BITS)-1);
  285.  
  286.                 // scan in the previous data for a match
  287.                 pHit = memfind(pPrevHit, pTestTail - pPrevHit, pTestHead, pTest
  288. Tail - pTestHead);
  289.  
  290.                 if (pHit==0)
  291.                         printf("!! bug source %x%x%x, dest %x%x%x, %d bytes",
  292. pPrevHit[0],
  293.                                 pPrevHit[1],pPrevHit[2],pTestHead[0],
  294.         pTestHead[1],   pTestHead[2],   pTestTail-pTestHead);
  295.  
  296.                 // on a mismatch or end of buffer, issued codes
  297.                 if (pHit==0
  298.                         || pHit==pTestHead
  299.                         || pTestTail-pTestHead>(1<<COUNT_BITS)+2
  300.                         || pTestTail==pEnd)
  301.                 {
  302.                         // issued the codes
  303.                         // first, check for short runs
  304.                         if (pTestTail-pTestHead < 4)
  305.                         {
  306. //printf("\nissue a char %x",pTestHead[0]);
  307.                                 Issue(pTestHead[0], bSpace);
  308.                                 pTestHead++;
  309.                         }
  310.                         // for longer runs, issue a run-code
  311.                         else
  312.                         {
  313.                                 // issue space char if required
  314.                                 if (bSpace) buf[len++] = ' ', bSpace = 0;
  315.  
  316.                                 unsigned int dist = pTestHead - pPrevHit;
  317.                                 unsigned int compound = (dist << COUNT_BITS) +
  318. pTestTail-pTestHead - 4;
  319.  
  320. if (dist>=(1<<DISP_BITS)) printf("\n!! error dist overflow");
  321. if (pTestTail-pTestHead-4>7) printf("\n!! error dist overflow");
  322.  
  323.                                 buf[len++] = 0x80 + (compound>>8);
  324.                                 buf[len++] = compound & 0xFF;
  325. //printf("\nissuing code for sequence len %d <%c%c%c>",pTestTail-pTestHead-1,pT
  326. estHead[0],pTestHead[1],pTestHead[2]);
  327. //printf("\n          <%x%x>",pOut[-2],pOut[-1]);
  328.                                 // and start again
  329.                                 pTestHead = pTestTail-1;
  330.                         }
  331.                         // start the search again
  332.                         pPrevHit = pBuffer;
  333.                 }
  334.                 // got a match
  335.                 else
  336.                 {
  337.                         pPrevHit = pHit;
  338.                 }
  339. //printf("pointers %x %x %x",pTestHead, pTestTail, pPrevHit);
  340.                 // when we get to the end of the buffer, don't inc past the end
  341.                 // this forces the residue chars out one at a time
  342.                 if (pTestTail==pEnd) pTestTail--;
  343.         }
  344.  
  345.         // clean up any dangling spaces
  346.         if (bSpace) buf[len++] = ' ';
  347.  
  348.  
  349.         // final scan to merge consecutive high chars together
  350.         int k;
  351.         for (i=k=0; i<len; i++,k++)
  352.         {
  353.                 buf[k] = buf[i];
  354.                 // skip the run-length codes
  355.                 if (buf[k]>=0x80 && buf[k]<0xC0)
  356.                         buf[++k] = buf[++i];
  357.                 // if we hit a high char marker, look ahead for another
  358.                 else if (buf[k]==1)
  359.                 {
  360.                         buf[k+1] = buf[i+1];
  361.                         while (i+2<len && buf[i+2]==1 && buf[k]<8)
  362.                         {
  363.                                 buf[k]++;
  364.                                 buf[k+buf[k]] = buf[i+3];
  365.                                 i+=2;
  366.                         }
  367.                         k += buf[k]; i++;
  368.                 }
  369.         }
  370.  
  371.         // delete original buffer
  372.         delete[] pBuffer;
  373.         len = k;
  374.  
  375.         return k;
  376. }
  377. /*
  378.         Decompress
  379.  
  380.         params: none
  381.  
  382.         action: make a new buffer
  383.                                         run through the source data
  384.                                         check the 4 cases:
  385.                                                 0,9...7F represent self
  386.                                                 1...8           escape n chars
  387.                                                 80...bf reference earlier run
  388.                                                 c0...ff space+ASCII
  389.  
  390. */
  391. unsigned
  392. tBuf::Decompress()
  393. {
  394.         // we "know" that all decompresses fit within 4096, right?
  395.         byte* pOut = new byte[6000];
  396.         byte* in_buf = buf;
  397.         byte* out_buf = pOut;
  398.  
  399.         int i,j;
  400.         for (j=i=0; j<len; )
  401.         {
  402.                 unsigned int c;
  403.  
  404.                 // take a char from the input buffer
  405.                 c = in_buf[j++];
  406.  
  407.                 // separate the char into zones: 0, 1...8, 9...0x7F, 0x80...0xB
  408. F, 0xC0...0xFF
  409.  
  410.                 // codes 1...8 mean copy that many bytes; for accented chars &
  411. binary
  412.                 if (c>0 && c<9)
  413.                         while(c--) out_buf[i++] = in_buf[j++];
  414.  
  415.                 // codes 0, 9...0x7F represent themselves
  416.                 else if (c<0x80)
  417.                         out_buf[i++] = c;
  418.  
  419.                 // codes 0xC0...0xFF represent "space + ascii char"
  420.                 else if (c>=0xC0)
  421.                                 out_buf[i++] = ' ', out_buf[i++] = c ^ 0x80;
  422.  
  423.                 // codes 0x80...0xBf represent sequences
  424.                 else
  425.                 {
  426.                         int m,n;
  427.                         c <<= 8;
  428.                         c += in_buf[j++];
  429.                         m = (c & 0x3FFF) >> COUNT_BITS;
  430.                         n = c & ((1<<COUNT_BITS) - 1);
  431.                         n += 3;
  432.                         while (n--)
  433.                         {
  434.                                 out_buf[i] = out_buf[i-m];
  435.                                 i++;
  436.                         }
  437.                 }
  438.         }
  439.         delete[] buf;
  440.         buf = pOut;
  441.         len = i;
  442.  
  443.         return i;
  444. }
  445.  
  446. unsigned tBuf::DuplicateCR()
  447. {
  448.         byte* pBuf = new byte[2*len];
  449.  
  450.         int k,j;
  451.         for (j=k=0; j<len; j++, k++)
  452.         {
  453.                 pBuf[k] = buf[j];
  454.                 if (pBuf[k]==0x0A) pBuf[k++] = 0x0D, pBuf[k] = 0x0A;
  455.         }
  456.         delete[] buf;
  457.         buf = pBuf;
  458.         len = k;
  459.         return k;
  460. }
  461.  
  462. // this nasty little beast removes really low ASCII and 0's
  463. // and handles the CR problem
  464. //
  465. // if a cr appears before a lf, then remove the cr
  466. // if a cr appears in isolation, change to a lf
  467. unsigned tBuf::RemoveBinary()
  468. {
  469.         byte* in_buf = buf;
  470.         byte* out_buf = new byte[len];
  471.  
  472.         int k,j;
  473.         for (j=k=0; j<len; j++,k++)
  474.         {
  475.                 // copy each byte
  476.                 out_buf[k] = in_buf[j];
  477.  
  478.                 // throw away really low ASCII
  479.                 if ((out_buf[k]>=0 && out_buf[k]<9)) k--;
  480.  
  481.                 // for CR
  482.                 if (out_buf[k]==0x0D)
  483.                 {
  484.                         // if next is LF, then drop it
  485.                         if (j<len-1 && in_buf[j+1]==0x0A)
  486.                                 k--;
  487.                         else // turn it into a LF
  488.                                 out_buf[k] = 0x0A;
  489.                 }
  490.         }
  491.         delete[] buf;
  492.         buf = out_buf;
  493.         len = k;
  494.         return k;
  495. }
  496.  
  497. void out_word(short w, FILE* fout)
  498. {
  499.         short m = SwapWord(w);
  500.         fwrite(&m,2,1,fout);
  501. }
  502. void out_long(long d, FILE* fout)
  503. {
  504.         long d1 = SwapLong(d);
  505.         fwrite(&d1,4,1,fout);
  506. }
  507.  
  508.  
  509.  
  510. //////////////////////////////////////////////////
  511. // Info Mode
  512. //////////////////////////////////////////////////
  513.  
  514. void Info(char* src)
  515. {
  516.         FILE* fin;
  517.         FILE* fout;
  518.         fin = fopen(src,"rb");
  519.  
  520.         if (fin==0)
  521.         {
  522.                 printf("problem opening source file %s", src);
  523. #if UNIX
  524.                 printf("\n");
  525. #endif
  526.                 exit(2);
  527.         }
  528.  
  529.         // just holds the first few bytes of the file
  530.         byte buf[0x100];
  531.         tDocHeader head;
  532.  
  533.         fread(&head, 1, DOCHEADSZ, fin);
  534.         if (strncmp((char *)&head.dwType, "REAd", 4) != 0
  535.             || strncmp((char *)&head.dwCreator, "TEXt", 4) != 0)
  536.         {
  537.           //printf("file contains %.4s, %.4s", (char *)&head.dwCreator, (char *
  538. )&head.dwType);
  539.                 printf("%s is not a DOC file", src);
  540. #if UNIX
  541.                 printf("\n");
  542. #endif
  543.                 exit(3);
  544.         }
  545.  
  546.  
  547.         WORD wPos;
  548.         int bPrivate = 0;
  549.         int bCategory = 0;
  550.  
  551.         // point to start of index
  552.         fseek(fin, 0x4E + 4, SEEK_SET);
  553.         // read the location of the first record
  554.         fread(&wPos, 1, 1, fin);
  555.         bPrivate = (int) (wPos & 0x10) / 16;
  556.         bCategory = (int) wPos & 0x0F;
  557.         printf("%s p%d c%02d",head.sName, bPrivate, bCategory);
  558.  
  559.         fclose(fin);
  560. }
  561.  
  562.  
  563. //////////////////////////////////////////////////
  564. // Modify Mode
  565. //////////////////////////////////////////////////
  566.  
  567. void Modify(char* src, char* title, int bQuiet, int bPrivate, int bCategory )
  568. {
  569.         FILE* fin;
  570.         fin = fopen(src,"r+b");
  571.  
  572.         if (fin==0)
  573.         {
  574.                 printf("problem opening source file %s", src);
  575. #if UNIX
  576.                 printf("\n");
  577. #endif
  578.                 exit(2);
  579.         }
  580.  
  581.         // just holds the first few bytes of the file
  582.         byte buf[0x100];
  583.         tDocHeader head;
  584.  
  585.         fread(&head, 1, DOCHEADSZ, fin);
  586.         if (strncmp((char *)&head.dwType, "REAd", 4) != 0
  587.             || strncmp((char *)&head.dwCreator, "TEXt", 4) != 0)
  588.         {
  589.           //printf("file contains %.4s, %.4s", (char *)&head.dwCreator, (char *
  590. )&head.dwType);
  591.                 printf("%s is not a DOC file", src);
  592. #if UNIX
  593.                 printf("\n");
  594. #endif
  595.                 exit(3);
  596.         }
  597.  
  598.         if(!bQuiet) printf("Modifying %s",src);
  599.  
  600.         if ( title[0] != '\0' )
  601.         {
  602.           if ( strcmp(head.sName, title) == 0)
  603.           {
  604.             if(!bQuiet) printf("\n  current title is similar");
  605.           }
  606.           else
  607.           {
  608.             if(!bQuiet) printf("\n  changing title from %s to %s", head.sName,
  609. title);
  610.             sprintf(head.sName,"%.31s",title);
  611.             head.sName[31] = 0;
  612.           }
  613.         }
  614.  
  615.         fseek(fin, 0, SEEK_SET);
  616.         fwrite(&head,1,DOCHEADSZ,fin);
  617.  
  618.  
  619.         WORD wNumRecs =  SwapWord(head.wNumRecs);  //  the number of records to
  620.  follow
  621.  
  622.  
  623.         WORD wPos;
  624.         int bPrivateCurr;
  625.         int bCategoryCurr;
  626.         int bChange = 0;
  627.         // point to start of index
  628.         fseek(fin, 0x4E + 4, SEEK_SET);
  629.         // read the location of the first record
  630.         fread(&wPos, 1, 1, fin);
  631.         bPrivateCurr = (int) (wPos & 0x10) / 16;
  632.         bCategoryCurr = (int) wPos & 0x0F;
  633.  
  634.         if ( bPrivate < 2 )
  635.         {
  636.           if ( bPrivate == bPrivateCurr)
  637.           {
  638.             if(!bQuiet) printf("\n  current private flag is similar");
  639.           }
  640.           else
  641.           {
  642.             if(!bQuiet) printf("\n  changing private flag from %d to %d", bPriv
  643. ateCurr, bPrivate);
  644.             bChange = 1;
  645.             wPos = wPos & 0xEF; // turn off the 5th bit
  646.             wPos =  wPos | (bPrivate * 16);
  647.           }
  648.         }
  649.  
  650.         if ( bCategory < 16 )
  651.         {
  652.           if ( bCategory == bCategoryCurr)
  653.           {
  654.             if(!bQuiet) printf("\n  current category is similar");
  655.           }
  656.           else
  657.           {
  658.             if(!bQuiet) printf("\n  changing category from %d to %d", bCategory
  659. Curr, bCategory);
  660.             bChange = 1;
  661.             wPos = wPos & 0xF0; // turn off the 1th to 4th bits
  662.             wPos =  wPos | bCategory;
  663.           }
  664.         }
  665.  
  666.         if(bChange) for ( int i = 0; i < wNumRecs; i++)
  667.         {
  668.           fseek(fin, 0x4E + 4 + i*8,  SEEK_SET);
  669.           fwrite(&wPos, 1, 1, fin);
  670.         }
  671.  
  672.         fclose(fin);
  673. }
  674.  
  675.  
  676. //////////////////////////////////////////////////
  677. // Decode Mode
  678. //////////////////////////////////////////////////
  679.  
  680. void Decode(char* src, char* dest, int bQuiet, int bBinary)
  681. {
  682.  
  683.         if ( dest[0] == '\0' )
  684.         {
  685.           strcpy(dest, "/dev/stdout");
  686.           bQuiet = 1;
  687.         }
  688.  
  689.         FILE* fin;
  690.         FILE* fout;
  691.         fin = fopen(src,"rb");
  692.  
  693.         if (fin==0)
  694.         {
  695.                 printf("problem opening source file %s", src);
  696. #if UNIX
  697.                 printf("\n");
  698. #endif
  699.                 exit(2);
  700.         }
  701.  
  702.         // just holds the first few bytes of the file
  703.         byte buf[0x100];
  704.         tDocHeader head;
  705.  
  706.         fread(&head, 1, DOCHEADSZ, fin);
  707.         if (strncmp((char *)&head.dwType, "REAd", 4) != 0
  708.             || strncmp((char *)&head.dwCreator, "TEXt", 4) != 0)
  709.         {
  710.           //printf("file contains %.4s, %.4s", (char *)&head.dwCreator, (char *
  711. )&head.dwType);
  712.                 printf("%s is not a DOC file", src);
  713. #if UNIX
  714.                 printf("\n");
  715. #endif
  716.                 exit(3);
  717.         }
  718.  
  719.         WORD bCompressed;
  720.         DWORD dwPos;
  721.         tDocRecord0 rec0;
  722.         // point to start of index
  723.         fseek(fin, 0x4E, SEEK_SET);
  724.         // read the location of the first record
  725.         fread(&dwPos, 4, 1, fin);
  726.         dwPos = SwapLong(dwPos);
  727.         fseek(fin, dwPos, SEEK_SET);
  728.         fread(&rec0, sizeof(rec0), 1, fin);
  729.         bCompressed = SwapWord(rec0.wVersion);
  730.         if (bCompressed!=1 && bCompressed!=2)
  731.                 printf("WARNING: unknown file compression type: %d", bCompresse
  732. d);
  733.         bCompressed--;
  734.  
  735.         fout = fopen(dest,"wb");
  736.         if (fout==0)
  737.         {
  738.                 printf("problem opening output file %s",dest);
  739. #if UNIX
  740.                 printf("\n");
  741. #endif
  742.                 exit(2);
  743.         }
  744.  
  745.  
  746.         DWORD dwLen;
  747.         fseek(fin,0,SEEK_END);
  748.         dwLen = ftell(fin);
  749.  
  750.         WORD nRecs;
  751.         nRecs = SwapWord(head.wNumRecs) - 1;
  752.  
  753.         // this is the main record buffer
  754.         // it knows how to stretch to accomodate the decompress
  755.         tBuf t;
  756.  
  757.         DWORD dwRecLen;
  758.         for (int i=0; i<nRecs; i++)
  759.         {
  760.                 // read the record offset
  761.                 fseek(fin, 0x56 + 8*i, SEEK_SET);
  762.                 fread(&dwPos, 4, 1, fin);
  763.                 dwPos = SwapLong(dwPos);
  764.  
  765.                 // read start of next record
  766.                 fseek(fin, 0x5E + 8*i, SEEK_SET);
  767.                 fread(&dwRecLen, 4, 1, fin);
  768.                 dwRecLen = SwapLong(dwRecLen);
  769.  
  770.                 // for the last, use the file len
  771.                 if (i==nRecs-1) dwRecLen = dwLen;
  772.  
  773.                 dwRecLen -= dwPos;
  774.  
  775.                 fseek(fin,dwPos,SEEK_SET);
  776.                 int n = fread(t.buf, 1, dwRecLen, fin);
  777.                 t.len = n;
  778.                 if(bCompressed)
  779.                         t.Decompress();
  780.  
  781. #ifndef UNIX
  782.                 // check for CR insert
  783.                 if (!bBinary)
  784.                         t.DuplicateCR();
  785. #endif
  786.  
  787.                 if(!bQuiet) printf("\rreconverting %s: record %d of %d",head.sN
  788. ame,i,nRecs);
  789.  
  790.                 fwrite(t.buf, 1, t.Len(), fout);
  791.         }
  792.  
  793.         fclose(fin);
  794.         fclose(fout);
  795.  
  796. }
  797.  
  798.  
  799.  
  800. //////////////////////////////////////////////////
  801. // Encode Mode
  802. //////////////////////////////////////////////////
  803.  
  804. void Encode(char* src, char* dest, char* title, int bQuiet, int bBinary,
  805.             int bReport, int bCompress, int bPrivate, int bCategory)
  806. {
  807.  
  808.         FILE* fin;
  809.         FILE* fout;
  810.         tDocHeader head1;
  811.  
  812.         if ( bPrivate > 1)
  813.         {
  814.           bPrivate = 0;
  815.         }
  816.  
  817.         if ( bCategory > 15)
  818.         {
  819.           bCategory = 0;
  820.         }
  821.  
  822.         if ( dest[0] == '\0' )
  823.         {
  824.           if(strrchr(src, '/'))
  825.           {
  826.             strcpy(dest, strrchr(src, '/')+1);
  827.           }
  828.           else
  829.           {
  830.             strcpy(dest, src);
  831.           }
  832.           strcat(dest, ".pdb");
  833.         }
  834.  
  835.         if ( title[0] == '\0' )
  836.         {
  837.           if(strrchr(src, '/'))
  838.           {
  839.             strcpy(title, strrchr(src, '/')+1);
  840.           }
  841.           else
  842.           {
  843.             strcpy(title, src);
  844.           }
  845.         }
  846.  
  847.         unsigned long index;
  848.         if(bPrivate)
  849.         {
  850.           index = 0x50000000; // private and dirty
  851.         }
  852.         else
  853.         {
  854.           index = 0x40000000; // dirty
  855.         }
  856.         index = index + (bCategory * 0x1000000); // set category
  857.         index = index + 0x6F8000; // unique_id=0x6f8000
  858.  
  859.         fin = fopen(src,"rb");
  860.         fout = fopen(dest,"wb");
  861.         if (fin==0 || fout==0)
  862.         {
  863.                 printf("problem opening files");
  864. #if UNIX
  865.                 printf("\n");
  866. #endif
  867.                 exit(2);
  868.         }
  869.  
  870.         fseek(fin,0,SEEK_END);
  871.         DWORD storySize = ftell(fin);
  872.         fseek(fin,0,SEEK_SET);
  873.  
  874.         DWORD   x;
  875.         WORD w;
  876.         long    recSize = 4096;
  877.         DWORD           z,numRecs;
  878.  
  879.         sprintf(head1.sName,"%.31s",title);
  880.         head1.sName[31] = 0;
  881.         if(!bQuiet) printf("Saving to %s as <%s>,%s%s compressed", dest, title,
  882.                         bBinary ? " binary mode," : "",
  883.                         bCompress ? "" : " not");
  884.  
  885.                 /*LocalWrite just writes to the new file the number of bytes st
  886. arting at the passed pointer*/
  887.  
  888.         head1.dwUnknown1 = 0;
  889.         strncpy((char *)&head1.dwTime1, "\x06\xD1\x44\xAE", 4);
  890.         strncpy((char *)&head1.dwTime2, "\x06\xD1\x44\xAE", 4);
  891.         head1.dwTime3 = 0;
  892.         head1.dwLastSync = 0;
  893.         head1.ofsSort = 0;
  894.         head1.ofsCatagories = 0;
  895.         strncpy((char *)&head1.dwCreator, "TEXt", 4);   // database creator
  896.         strncpy((char *)&head1.dwType, "REAd", 4);      // database type
  897.         head1.dwUnknown2 = 0;
  898.         head1.dwUnknown3 = 0;
  899.  
  900.  
  901.  
  902.         z = (int) (storySize/(long) recSize);
  903.         if (((long) z * recSize) < storySize)
  904.                 z ++;
  905.  
  906.         numRecs = z;
  907.         z ++;
  908.  
  909.         head1.wNumRecs = SwapWord(z);           //  the number of records to fo
  910. llow
  911.         fwrite(&head1,1,DOCHEADSZ,fout);
  912.         x = 0x50L + (long) z * 8;
  913.  
  914.         out_long(x,fout);               // start writing the record offsets
  915.         out_long(index,fout);
  916.         x += 0x0010L;
  917.  
  918.         index++;
  919.         z--;
  920.  
  921.         while(z--) {
  922.                 out_long(x,fout);               //more record offsets
  923.                 out_long(index++,fout);         // the attributes + ID's
  924.                 x += 0x1000L;
  925.         }
  926.         // one more word.....
  927.         out_word(0,fout);
  928.  
  929.  
  930.         tDocRecord0 rec0;
  931.         rec0.wVersion = SwapWord(bCompress ? 2 : 1);
  932.         rec0.wSpare = 0;
  933.         rec0.dwStoryLen = SwapLong(storySize);
  934.         rec0.wNumRecs = SwapWord(SwapWord(head1.wNumRecs) - 1);
  935.         rec0.wRecSize = SwapWord(recSize);
  936.         rec0.dwSpare2 = 0;
  937.  
  938.         fwrite(&rec0,1,sizeof(rec0),fout);
  939.  
  940.         int n = recSize;
  941.         // dump the whole story into the new file
  942.         int recNum = 0;
  943.         if(!bQuiet) printf("\n");
  944.  
  945.         tBuf buf;
  946.  
  947.         while(recNum < numRecs)
  948.                 {
  949.                 long pos;
  950.                 pos = ftell(fout);
  951.                 fseek(fout, 0x56 + 8*recNum, SEEK_SET);
  952.                 if (recNum!=numRecs) out_long(pos,fout);
  953.                 fseek(fout, pos, SEEK_SET);
  954.  
  955.                 int nOrg;
  956.  
  957.                 buf.Clear();
  958.                 nOrg = n = fread(buf.buf,1,4096,fin);
  959.                 buf.len = n;
  960.                 if (n==0) break;
  961.  
  962.                 if (!bBinary)
  963.                         buf.RemoveBinary();
  964.                 if (bCompress)
  965.                         buf.Compress();
  966.                 n = fwrite(buf.buf,1,buf.Len(),fout);
  967.  
  968.                 if(!bQuiet) printf("\rconverting record %d of %d",recNum+1,numR
  969. ecs);
  970.                 if (bReport && n && bCompress)
  971.                         if(!bQuiet) printf("\noriginal %d bytes, compressed to
  972. %d bytes, ratio: %f5.1\n",
  973.                                 nOrg, n, 100. * n / nOrg);
  974.                 recNum++;
  975.                 }
  976.  
  977.         fclose(fin);
  978.         fclose(fout);
  979. }
  980.  
  981.  
  982.  
  983. //////////////////////////////////////////////////
  984. // Main Program
  985. //////////////////////////////////////////////////
  986.  
  987. int
  988. main(int argc, char** argv)
  989. {
  990.         int iArg = 1;
  991.         int bEncode = 1;
  992.         int bDecode = 0;
  993.         int bInfo   = 0;
  994.         int bModify = 0;
  995.         int bBinary = 0;
  996.         int bReport = 0;
  997.         int bCompress = 1;
  998.         int bPrivate = 2;
  999.         int bCategory = 16;
  1000.         int bQuiet = 0;
  1001.         char filein[250]="";
  1002.         char fileout[250]="";
  1003.         char title[250]="";
  1004.  
  1005.         if ( ! SwapChoose()) {
  1006.           printf("\nfailed to select proper byte swapping algorithm");
  1007. #if UNIX
  1008.           printf("\n");
  1009. #endif
  1010.           exit(1);
  1011.         }
  1012.  
  1013.         while (iArg < argc)
  1014.         {
  1015.           if (argv[iArg][0] == '-')
  1016.           {
  1017.             switch(argv[iArg][1])
  1018.             {
  1019.               case 'e' :
  1020.                 bEncode = 1;
  1021.                 bDecode = 0;
  1022.                 bInfo   = 0;
  1023.                 bModify = 0;
  1024.                 break;
  1025.               case 'd' :
  1026.                 bEncode = 0;
  1027.                 bDecode = 1;
  1028.                 bInfo   = 0;
  1029.                 bModify = 0;
  1030.                 break;
  1031.               case 'i':
  1032.                 bEncode = 0;
  1033.                 bDecode = 0;
  1034.                 bInfo   = 1;
  1035.                 bModify = 0;
  1036.                 break;
  1037.               case 'm':
  1038.                 bEncode = 0;
  1039.                 bDecode = 0;
  1040.                 bInfo   = 0;
  1041.                 bModify = 1;
  1042.                 break;
  1043.               case 'b' :
  1044.                 bBinary = 1;
  1045.                 break;
  1046.               case 'r' :
  1047.                 bReport = 1;
  1048.                 break;
  1049.               case 'n' :
  1050.                 bCompress = 0;
  1051.               case 'p' :
  1052.                 bPrivate = 1;
  1053.                 if (argv[iArg][2]=='0')
  1054.                    bPrivate = 0;
  1055.                 break;
  1056.               case 'c' :
  1057.                 char nb[3];
  1058.                 nb[0] = argv[iArg][2];
  1059.                 nb[1] = argv[iArg][3];
  1060.                 nb[2] = argv[iArg][4];
  1061.                 bCategory = atoi(nb);
  1062.                 break;
  1063.               case 'o' :
  1064.                 iArg++;
  1065.                 strcpy(fileout, argv[iArg]);
  1066.                 break;
  1067.               case 't' :
  1068.                 iArg++;
  1069.                 strcpy(title, argv[iArg]);
  1070.                 break;
  1071.               case 'q' :
  1072.                 bQuiet = 1;
  1073.                 break;
  1074.             }
  1075.           }
  1076.           else if (filein[0] == '\0')
  1077.           {
  1078.             strcpy(filein, argv[iArg]);
  1079.           }
  1080.           else if (fileout[0] == '\0')
  1081.           {
  1082.             strcpy(fileout, argv[iArg]);
  1083.           }
  1084.           else if (title[0] == '\0')
  1085.           {
  1086.             strcpy(title, argv[iArg]);
  1087.           }
  1088.           iArg++;
  1089.         }
  1090.  
  1091.         if (bInfo && filein[0] != '\0')
  1092.         {
  1093.                 Info(filein);
  1094.         }
  1095.         else if (bModify && filein[0] != '\0')
  1096.         {
  1097.                 Modify(filein, title, bQuiet, bPrivate, bCategory);
  1098.         }
  1099.         else if (bDecode && filein[0] != '\0')
  1100.         {
  1101.                 Decode(filein, fileout, bQuiet, bBinary);
  1102.         }
  1103.         else if (bEncode && filein[0] != '\0')
  1104.         {
  1105.                 Encode(filein, fileout, title, bQuiet, bBinary, bReport, bCompr
  1106. ess, bPrivate, bCategory);
  1107.         }
  1108.         else
  1109.         {
  1110.            printf("MakeDoc ver 0.8\n");
  1111.            printf("\nmakedoc [-q] [-n] [-b] [-p#] [-c#] [-o <pdb-file>] [-t <pd
  1112. b-title>] <text-file>");
  1113.            printf("\nmakedoc [-q] [-n] [-b] [-p#] [-c#] <text-file> <pdb-file>
  1114. <pdb-title>");
  1115.            printf("\n   encode text file to DOC format");
  1116.            printf("\n");
  1117.            printf("\nmakedoc -d [-q] [-b] [-o <txt-file>] <pdb-file>");
  1118.            printf("\nmakedoc -d [-q] [-b] <pdb-file> <txt-file>");
  1119.            printf("\n   decode DOC file back to text file");
  1120.            printf("\n");
  1121.            printf("\nmakedoc -i <pdb-file>");
  1122.            printf("\n   print the DOC info (title, private flag, category)");
  1123.            printf("\n");
  1124.            printf("\nmakedoc -m [-q] [-p#] [-c#] [-t <pdb-title>] <pdb-file>");
  1125.            printf("\n   modify title, private flag, category");
  1126.            printf("\n");
  1127.            printf("\n   -q quiet mode");
  1128.            printf("\n   -n builds the .pdb file without compression");
  1129.            printf("\n   -b option compresses/decompresses binary");
  1130.            printf("\n   -p private, #=0 private off (default=off)");
  1131.            printf("\n   -c category, #=[0-15] category number (default=0)");
  1132.            printf("\n   -o output filename (encoding mode default=<text-file>.p
  1133. db)");
  1134.            printf("\n                      (decoding mode default=stdout)");
  1135.            printf("\n   -t title (max=31, default=<text-file>)");
  1136. #if UNIX
  1137.            printf("\n");
  1138. #endif
  1139.            exit(1);
  1140.         }
  1141. #if UNIX
  1142.         if(!bQuiet) printf("\n");
  1143. #endif
  1144.         exit(0);
  1145. }
  1146.  
  1147.